/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.formserver.viewmodel.util;


import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspAssociationKey;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.element.GspEnumValue;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.entity.element.GspCommonAssociation;
import com.inspur.edp.formserver.viewmodel.DotNetToJavaStringHelper;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.viewmodel.exception.VoModelErrorCodes;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UseTypeInfo;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnInfo;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
import com.inspur.edp.udt.designtime.api.entity.enumtype.UseType;
import io.iec.edp.caf.commons.utils.CollectionUtils;

/**
 * 更新udt字段
 */
public class UpdateVoElementUtil {
    private boolean isVirtual = true;

    /**
     * 根据引用的udt元数据更新字段(模板约束均更新)
     *
     * @param element
     * @param udt
     */
    public final void UpdateElementWithRefUdt(GspViewModelElement element, UnifiedDataTypeDef udt, boolean isFirstChoose) {
        element.setUdtID(udt.getId());
        element.setUdtName(udt.getName());

        // 其他属性
        if (udt instanceof ComplexDataTypeDef) {
            UpdateComplexDataTypeDefProperties(element, (ComplexDataTypeDef) udt);
        } else if (udt instanceof SimpleDataTypeDef) {
            UpdateSimpleDataTypeDefProperties(element, (SimpleDataTypeDef) udt, isFirstChoose);
        }
    }

    /**
     * 转换columnInfo为childElement
     *
     * @param info
     * @param prefix
     * @param ele    映射字段
     */
    public final void MapColumnInfoToField(ColumnInfo info, String prefix, GspViewModelElement ele) {
        if (ViewModelUtils.checkNull(prefix)) {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1050, null);
        }
        String newLabelId = prefix + "_" + info.getCode();
        ele.setLabelID(newLabelId);
        ele.setCode(newLabelId);
        ele.setName(info.getName());
        ele.setMDataType(info.getMDataType());
        ele.setDefaultValue(info.getDefaultValue());
        ele.setLength(info.getLength());
        ele.setPrecision(info.getPrecision());
    }

    ///#region 单值

    /**
     * 根据单值udt更新字段的其他属性
     *
     * @param element
     * @param sUdt
     * @param isFirstChoose 是否首次选择
     */
    private void UpdateSimpleDataTypeDefProperties(GspViewModelElement element, SimpleDataTypeDef sUdt, boolean isFirstChoose) {
        if (DotNetToJavaStringHelper.isNullOrEmpty(element.getCode())) {
            element.setCode(sUdt.getCode());
        }
        if (DotNetToJavaStringHelper.isNullOrEmpty(element.getName())) {
            element.setName(sUdt.getName());
        }

        if (isFirstChoose || IsConstraint(sUdt, "DataType")) {
            element.setMDataType(sUdt.getMDataType());
        }
        if (isFirstChoose || IsConstraint(sUdt, "Length")) {
            element.setLength(sUdt.getLength());
        }
        if (isFirstChoose || IsConstraint(sUdt, "Precision")) {
            element.setPrecision(sUdt.getPrecision());
        }
        if (isFirstChoose || IsConstraint(sUdt, "ObjectType")) {
            element.setObjectType(sUdt.getObjectType());
            // 关联
            if (element.getChildAssociations() == null) {
                element.setChildAssociations(new GspAssociationCollection());
            }

            IGspCommonField belongElement = (!element.getChildAssociations().isEmpty()) ?
                    element.getChildAssociations().get(0).getBelongElement() : null;

            GspAssociationCollection assos = element.getChildAssociations().clone(belongElement);

            element.getChildAssociations().clear();
            if (!CollectionUtils.isEmpty(sUdt.getChildAssociations())) {
                for (GspAssociation item : sUdt.getChildAssociations()) {
                    GspAssociation beAsso = assos.stream()
                            .filter(asso -> asso.getId().equals(item.getId()))
                            .findFirst().orElse(null);
                    element.getChildAssociations().add(ConvertUdtAssociation(item, element, beAsso, isFirstChoose));
                }
            }

            element.setEnumIndexType(sUdt.getEnumIndexType());
            // 枚举
            element.getContainEnumValues().clear();
            if (!CollectionUtils.isEmpty(sUdt.getContainEnumValues())) {
                for (GspEnumValue item : sUdt.getContainEnumValues()) {
                    element.getContainEnumValues().add(item);
                }
            }
        }
        if (isFirstChoose || IsConstraint(sUdt, "DefaultValue")) {
            element.setDefaultValue(sUdt.getDefaultValue() == null ? null : sUdt.getDefaultValue().toString());
        }
        if (isFirstChoose || IsConstraint(sUdt, "IsRequired")) {
            element.setIsRef(sUdt.getIsRequired());
        }
    }

    /**
     * 是否约束
     */
    private boolean IsConstraint(SimpleDataTypeDef sUdt, String propertyName) {
        if (sUdt.getPropertyUseTypeInfos().containsKey(propertyName)) {

            UseTypeInfo type = sUdt.getPropertyUseTypeInfos().get(propertyName);
            return type.getPropertyUseType() == UseType.AsConstraint;
        } else {
            throw new ViewModelException(VoModelErrorCodes.GSP_VIEWOBJECT_MODEL_1051, null, propertyName);
        }
    }


    ///#endregion


    ///#region 多值

    /**
     * 根据多值udt更新字段的其他属性
     *
     * @param element
     * @param cUdt
     */
    private void UpdateComplexDataTypeDefProperties(GspViewModelElement element, ComplexDataTypeDef cUdt) {
        if (DotNetToJavaStringHelper.isNullOrEmpty(element.getCode())) {
            element.setCode(cUdt.getCode());
        }
        if (DotNetToJavaStringHelper.isNullOrEmpty(element.getName())) {
            element.setName(cUdt.getName());
        }

        UdtElement newElement;
        if (cUdt.getElements().size() == 1 && cUdt.getDbInfo().getMappingType() != ColumnMapType.SingleColumn) {
            newElement = (UdtElement) cUdt.getElements().get(0);
        } else {
            newElement = new UdtElement(cUdt.getPropertys());
        }

        element.setObjectType(newElement.getObjectType());

        // 若为[单一列]的映射关系，可能导致超长，需把数据类型改为[Text]
        if (cUdt.getDbInfo().getMappingType() == ColumnMapType.SingleColumn) {
            element.setMDataType(GspElementDataType.Text);
            element.setLength(0);
            element.setPrecision(0);
        } else {
            element.setMDataType(newElement.getMDataType());
            element.setLength(newElement.getLength());
            element.setPrecision(newElement.getPrecision());
        }
        element.setDefaultValue(newElement.getDefaultValue());
        element.getChildAssociations().clear();
        element.getContainEnumValues().clear();
    }

    ///#endregion


    ///#region 关联
    private GspAssociation ConvertUdtAssociation(GspAssociation udtAsso, IGspCommonElement ele, GspAssociation beAsso, boolean isFirstChoose) {
        GspCommonAssociation asso = new GspCommonAssociation();
        asso.setId(udtAsso.getId());
        asso.setRefModel((ele.getBelongObject() != null) ? ele.getBelongObject().getBelongModel() : null);
        asso.setRefModelCode(udtAsso.getRefModelCode());
        asso.setRefModelID(udtAsso.getRefModelID());
        asso.setRefModelName(udtAsso.getRefModelName());
        asso.setRefModelPkgName(udtAsso.getRefModelPkgName());
        asso.setRefObjectCode(udtAsso.getRefObjectCode());
        asso.setRefObjectID(udtAsso.getRefObjectID());
        asso.setRefObjectName(udtAsso.getRefObjectName());
        if (!CollectionUtils.isEmpty(udtAsso.getKeyCollection())) {
            for (GspAssociationKey key : udtAsso.getKeyCollection()) {
                asso.getKeyCollection().add(ConvertUdtAssoKey(key, ele));
            }
        }

        if (isFirstChoose) {
            if (!CollectionUtils.isEmpty(udtAsso.getRefElementCollection())) {
                for (IGspCommonField refEle : udtAsso.getRefElementCollection()) {
                    asso.getRefElementCollection().add(ConvertUdtRefElement((UdtElement)refEle, ele.getLabelID()));
                }
            }
        } else {
            GspFieldCollection udtRefElements = udtAsso.getRefElementCollection().clone(null, udtAsso);
            // udt带出
            if (beAsso != null && !CollectionUtils.isEmpty(beAsso.getRefElementCollection())) {
                for (IGspCommonField refEle : beAsso.getRefElementCollection()) {
                    if (refEle.getIsFromAssoUdt()) {
                        IGspCommonField refElement = udtRefElements.stream()
                                .filter(item -> item.getRefElementId().equals(refEle.getRefElementId()))
                                .findFirst().orElse(null);

                        udtRefElements.remove(refElement);
                        // udt仍包含，则加上；udt上已删，则不加。
                        if (refElement != null) {
                            IGspCommonElement refEle2 = ConvertUdtRefElement((UdtElement)refElement, ele.getLabelID());
                            refEle2.setID(refEle.getID());
                            asso.getRefElementCollection().add(refEle2);
                        }
                    } else {
                        asso.getRefElementCollection().add(refEle);
                    }
                }
            }
            if (!udtRefElements.isEmpty()) {
                for (IGspCommonField refEle : udtRefElements) {
                    asso.getRefElementCollection().add(ConvertUdtRefElement((UdtElement) refEle, ele.getLabelID()));
                }
            }
        }

        return asso;
    }

    private GspAssociationKey ConvertUdtAssoKey(GspAssociationKey udtKey, IGspCommonElement ele) {
        GspAssociationKey key = new GspAssociationKey();
        key.setSourceElement(udtKey.getSourceElement());
        key.setSourceElementDisplay(udtKey.getSourceElementDisplay());
        key.setTargetElement(ele.getID());
        key.setTargetElementDisplay(ele.getName());
        return key;
    }

    private IGspCommonElement ConvertUdtRefElement(UdtElement udtEle, String prefix) {
        GspViewModelElement bizEle = new GspViewModelElement();
        bizEle.setID(udtEle.getID());
        String newLabelId = prefix + "_" + udtEle.getLabelID();
        bizEle.setLabelID(newLabelId);
        bizEle.setCode(udtEle.getCode());
        bizEle.setName(udtEle.getName());
        bizEle.setMDataType(udtEle.getMDataType());
        bizEle.setObjectType(udtEle.getObjectType());
        bizEle.setLength(udtEle.getLength());
        bizEle.setPrecision(udtEle.getPrecision());
        bizEle.setRefElementId(udtEle.getRefElementId());
        bizEle.setIsRefElement(true);
        bizEle.setIsFromAssoUdt(true);

        // udt相关
        bizEle.setIsUdt(udtEle.getIsUdt());
        bizEle.setUdtID(udtEle.getUdtID());
        bizEle.setUdtName(udtEle.getUdtName());
        bizEle.setUdtPkgName(udtEle.getUdtPkgName());
        if (udtEle.getObjectType() == GspElementObjectType.Enum) {
            bizEle.setContainEnumValues(udtEle.getContainEnumValues());
        }
        // 虚拟vo字段
        if (isVirtual) {
            bizEle.setIsVirtualViewElement(true);
            bizEle.setIsVirtual(bizEle.getIsVirtualViewElement());
            bizEle.setMapping(null);
        }
        return bizEle;
    }
    ///#endregion
}